//
// File:	Parser.hpp
// Author:	Thomas TISSOT-DUPONT
// Login:	<thomas.tissotdupont@free.fr>
//
// Create:	02/02/2010 at 07:56:34
// Purpose:	
//
#ifndef PARSER_HPP
#define PARSER_HPP

#include <map>
#include <list>
#include <string>
#include <sstream>
#include <fstream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include "Variant.hpp"

class Parser
{
public:
	//------------------------------------------------------------------
	// File Utility Class
	//------------------------------------------------------------------
	class File
	{
	public:
		static bool					GetContents(const std::string &filePath, std::string &bufferTarget);
		static bool					WriteContents(const std::string &filePath, const std::string &buffer);
	
	private:
		static const std::size_t	stBufferSize;
	};

	//------------------------------------------------------------------
	// Tokenizer Class
	//------------------------------------------------------------------
	class Tokenizer
	{
	public:
								Tokenizer(const std::string &blanks = "", const std::string &separators = "");

	public:
		void					Tokenize(const std::string &bufferData, std::list<std::string> &listTarget);

	public:
		void					AddBlanks(const std::string &);
		void					AddSeparators(const std::string &);

	private:
		void					TokenizeBlanks(const std::string &bufferData, std::list<std::string> &listTarget);
		void					TokenizeSeparators(const std::string &bufferData, std::list<std::string> &listTarget);

	private:
		std::string				m_blanks;
		std::string				m_separators;
	};
	
	//------------------------------------------------------------------
	// Parser Element Class
	//------------------------------------------------------------------
	class Element
	{
	public:
													Element(const std::string &name = "");
													~Element();

	public:
		void										SetName(const std::string &name);
		const std::string							&GetName() const;

	public:
		void										AddKeyValue(const std::string &key, const std::string &value);
		const std::map<std::string, Variant>		&GetKeyValues() const;
		bool										HasKey(const std::string &key) const;
		bool										HasKeys(const std::list<std::string> &keys) const;
		Variant										GetValueForKey(const std::string &key, const Variant &defaultValue = Variant()) const;

	public:
		void										AddChild(Element *);
		const std::list<Element *>					&GetChildren() const;
		Element										*FindChild(const std::string &name) const;
		std::list<const Element *>					FindChildren(const std::string &name) const;
		bool										HasChildren(const std::list<std::string> &names) const;

	public:
		void										Dump(int level = 8) const;

	private:
		std::string									m_name;
		std::map<std::string, Variant>				m_keyvalues;
		std::list<Element *>						m_children;
	};

public:
								Parser();
								~Parser();

public:
	bool						ParseFromFile(const std::string &filePath);
	bool						ParseFromBuffer(const std::string &fileBuffer);
	bool						ParseFromTokensList(std::list<std::string> &tokensList);

public:
	const Element				&GetRootElement() const;

private:
	bool						ParseBlock(std::list<std::string> &, Element *);
	bool						ParserKeyValue(std::list<std::string> &, Element *);

public:
	void						Clear();

protected:
	Element						m_rootElement;

protected:
	static const std::string	stBlank;
	static const std::string	stOpenBlock;
	static const std::string	stCloseBlock;
	static const std::string	stKeyEnd;
	static const std::string	stValueEnd;
	static const std::string	stTab;
	static const std::string	stCR;
	static const std::string	stNewLine;
	static const std::string	stSpace;
};

#endif //!PARSER_HPP
